package com.henry.base.concurrency;

public class RingBuffer<T> {

    private final static int bufferSize = 1<<21;
    private Object[] buffer = new Object[bufferSize];
    private volatile int head = 0;
    private volatile int tail = 0;

    private Boolean empty() {
        return head == tail;
    }
    private Boolean full() {
        return (tail + 1) % bufferSize == head;
    }
    public Boolean put(T v) {
//        int copyHead = head;
//        (tail + 1) % bufferSize == copyHead
        if (full()) {
//            System.out.println("put "+v +" false");
            return false;
        }
        buffer[tail] = v;
        tail = (tail + 1) % bufferSize;
//        System.out.println("put "+v +" sucess");
        return true;
    }
    public T get() {
//        int copyTail = tail;
//        head == copyTail
        if (empty()) {
//            System.out.println("get false");
            return null;
        }
        Object result = buffer[head];
        head = (head + 1) % bufferSize;
//        System.out.println("get "+result+" sucess");
        return (T) result;
    }
    public Object[] getAll() {
        if (empty()) {
            return new Object[0];
        }
        int copyTail = tail;
        int cnt = head < copyTail ? copyTail - head : bufferSize - head + copyTail;
        Object[] result = new Object[cnt];
        if (head < copyTail) {
            for (int i = head; i < copyTail; i++) {
                result[i - head] = buffer[i];
            }
        } else {
            for (int i = head; i < bufferSize; i++) {
                result[i - head] = buffer[i];
            }
            for (int i = 0; i < copyTail; i++) {
                result[bufferSize - head + i] = buffer[i];
            }
        }
        head = copyTail;
        return result;
    }


    public static void main(String[] args) throws InterruptedException {
        RingBuffer<Integer> ringBuffer = new RingBuffer<>();
        int max = 10000000;
        Thread t1 = new Thread(()->{
            int putTimes =0;
            for (int i = 0; i < max; ) {
                putTimes++;
                if (ringBuffer.put(i)) {
                    i++;
                }
            }
            System.out.println("putTimes "+putTimes);
        });

        Thread t2 = new Thread(()->{
            int getTimes =0;
            for (int i = 0; i < max; ) {
                getTimes++;
//                Integer n = ringBuffer.get();
                if (ringBuffer.get() !=null) {
                    i++;
                }
            }
            System.out.println("getTimes "+getTimes);
        });
        long l = System.currentTimeMillis();
        t1.start();
        Thread.sleep(30);
        t2.start();
        t1.join();
        System.out.println("-------------------");
        t2.join();
        long l2 = System.currentTimeMillis();
        System.out.println(l2-l+"ms");
    }
}